package gouhuo.allbugs.top.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import gouhuo.allbugs.top.common.BusinessException;
import gouhuo.allbugs.top.common.ErrorCode;
import gouhuo.allbugs.top.mapper.VisitorMapper;
import gouhuo.allbugs.top.model.domain.Visitor;
import gouhuo.allbugs.top.model.request.visitor.VisitorAddRequest;
import gouhuo.allbugs.top.model.request.visitor.VisitorMsgAddRequest;
import gouhuo.allbugs.top.model.vo.UserVO;
import gouhuo.allbugs.top.service.UserService;
import gouhuo.allbugs.top.service.VisitorService;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static gouhuo.allbugs.top.constant.RedisConstants.*;

/**
 * @author 15294780204
 * @description 针对表【visitor(访客表)】的数据库操作Service实现
 * @createDate 2023-05-01 18:07:13
 */
@Service
public class VisitorServiceImpl extends ServiceImpl<VisitorMapper, Visitor>
        implements VisitorService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private UserService userService;

    @Override
    public boolean addVisitor(VisitorAddRequest visitorAddRequest) {
        Long toId = visitorAddRequest.getToId();
        Long fromId = visitorAddRequest.getFromId();
        String fromUrl = visitorAddRequest.getFromUrl();
        if (fromUrl == null || toId == null || fromId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        LambdaQueryWrapper<Visitor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Visitor::getToId, toId).eq(Visitor::getFromId, fromId);
        Visitor visitor = getOne(lambdaQueryWrapper);
        boolean success, loop = false, isFirst = false;
        if (visitor == null) {
            success = save(BeanUtil.copyProperties(visitorAddRequest, Visitor.class));
            loop = true;
            isFirst = true;
        } else {
            success = update().setSql("amount = amount + 1").eq("id", visitor.getId()).update();
            if (!visitor.getFromUrl().equals(fromUrl)) {
                loop = true;
                update().setSql("fromUrl = '" + fromUrl + "'").eq("id", visitor.getId()).update();
            }
        }
        Gson gson = new Gson();
        String simpleKey = VISITOR_SET_SIMPLE_KEY + toId;
        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
        if (isFirst) {
            //存储最近5名访客的头像
            if (opsForHash.size(simpleKey) == 5) {
                Set<Object> keys = opsForHash.keys(simpleKey);
                for (Object key : keys) {
                    opsForHash.delete(simpleKey, key);
                    break;
                }
            }
            opsForHash.put(simpleKey, "visitor" + fromId, gson.toJson(visitorAddRequest));
            //存储历史访客的信息
            String fullKey = VISITOR_SET_FULL_KEY + toId + ":visitor" + fromId;
            UserVO userVO = BeanUtil.copyProperties(userService.getById(fromId), UserVO.class);
            //将user对象转化为HashMap存储
            Map<String, Object> userMap = BeanUtil.beanToMap(userVO, new HashMap<>(),
                    CopyOptions.create() //在存储为map时要保证值全为String
                            .setIgnoreNullValue(true) //忽略空值
                            .setFieldValueEditor((fieldName, fieldValue) -> fieldValue == null ? "" : fieldValue.toString()));
            //将该对象存储到redis
            stringRedisTemplate.opsForHash().putAll(fullKey, userMap);
            //设置key的有效期
            stringRedisTemplate.expire(fullKey, VISITOR_SET_FULL_TTL, TimeUnit.DAYS);
        } else {
            String str = (String) opsForHash.get(simpleKey, "visitor" + fromId);
            if (loop) {
                VisitorMsgAddRequest visitorMsgAddRequest = gson.fromJson(str, VisitorMsgAddRequest.class);
                visitorMsgAddRequest.setFromUrl(fromUrl);
                opsForHash.put(simpleKey, "visitor" + fromId, gson.toJson(visitorMsgAddRequest));
            } else {
                opsForHash.put(simpleKey, "visitor" + fromId, str == null ? "" : str);
            }
        }
        return success;
    }

    @Override
    public List<UserVO> visitorFull(Integer userId) {
        String key = VISITOR_SET_FULL_KEY + userId + ":*";
        Set<String> keys = stringRedisTemplate.keys(key);
        if (keys == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "访客列表查询失败");
        }
        List<UserVO> list = new ArrayList<>();
        if (keys.size() == 0) {
            return list;
        }
        for (String k : keys) {
            Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(k);
            UserVO userVO = BeanUtil.fillBeanWithMap(map, new UserVO(), false);
            list.add(userVO);
        }
        return list;
    }

    @Override
    public void addVisitorMsg(VisitorMsgAddRequest visitorMsgAddRequest) {
        Long toId = visitorMsgAddRequest.getToId();
        Long fromId = visitorMsgAddRequest.getFromId();
        String fromName = visitorMsgAddRequest.getFromName();
        String fromUrl = visitorMsgAddRequest.getFromUrl();
        String message = visitorMsgAddRequest.getMessage();
        if (fromName == null || message == null || fromUrl == null || toId == null || fromId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (message.length() > 18) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "留言长度不符合要求");
        }
        boolean update = update().setSql("message='" + message + "'").eq("toId", toId).eq("fromId", fromId).update();
        if (!update) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "留言失败");
        }
        String simpleKey = VISITOR_SET_SIMPLE_KEY + toId;
        stringRedisTemplate.opsForHash().put(simpleKey, "visitor" + fromId, new Gson().toJson(visitorMsgAddRequest));
    }

}
